
package kalkon;

import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.ResourceBundle;
import nu.xom.Builder;
import nu.xom.Document;
import nu.xom.Element;
import nu.xom.Elements;
import nu.xom.ParsingException;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLReaderFactory;

/**
 *
 * @author tommz
 */
public class ConfigurationLoader {

    private ResourceBundle bundle = ResourceBundle.getBundle("kalkon.messages");

    private static String ns = "http://code.google.com/p/kalkon/config";

    /**
     * Loads XML file and validate it with XML Schema. Schemas are loaded from
     * resources.
     * @param input
     * @return
     */
    public static Document loadXMLvalidate(InputStream input){
        Document doc = null;

        try {

            XMLReader xerces = XMLReaderFactory.createXMLReader("org.apache.xerces.parsers.SAXParser");
            xerces.setFeature("http://apache.org/xml/features/validation/schema", true);
            
            xerces.setEntityResolver(new EntityResolver() {

                public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
                    String location = systemId.substring("file://".length());
                    InputSource ret = new InputSource(location.getClass().getResourceAsStream(location));
                    return ret;
                }
            });

            xerces.setProperty("http://apache.org/xml/properties/schema/external-schemaLocation",
                    "http://code.google.com/p/kalkon/config /kalkon/schemas/configuration.xsd " +
                    "http://code.google.com/p/kalkon/database /kalkon/schemas/database.xsd " +
                    "http://code.google.com/p/kalkon/internalClub /kalkon/schemas/internalClub.xsd "+
                    "http://code.google.com/p/kalkon/internalConcerts /kalkon/schemas/internalConcerts.xsd");

            Builder parser = new Builder(xerces, true);

            doc = parser.build(input);
        }catch (ParsingException ex) {
            System.err.println(ex.toString());
            return null;
        } catch (IOException ex) {
            System.err.println(ex.toString());
            return null;
        } catch (SAXException ex) {
            System.err.println(ex.toString());
            return null;
        }

        return doc;
    }

    /**
     * Reads Configuration class from file.
     * @param input
     * @return
     */
    public Configuration loadConfiguration(InputStream input) {

        Document doc = loadXMLvalidate(input);

        if(doc == null){
            return null;
        }

        Configuration conf = new Configuration();

        Element root = doc.getRootElement();

        Elements modules = root.getFirstChildElement("inputModules", ns)
                .getChildElements("module", ns);

        Map<String, String> modulesMap = new HashMap<String, String>(modules.size());

        for (int m = 0; m < modules.size(); m++) {
            Element module = modules.get(m);

            String javaPath = module.getFirstChildElement("javaPath", ns).getValue();
            String jarPath = module.getFirstChildElement("jarPath", ns).getValue();

            modulesMap.put(javaPath, jarPath);

        }

        conf.setInputModules(modulesMap);

        Element outputElement = root.getFirstChildElement("output", ns);

        String outputMethodString = outputElement.getFirstChildElement("method", ns).getValue();

        if (outputMethodString.equals("ftp")) {
            conf.setOutputMethod(Configuration.OutputMethods.FTP);
        } else if (outputMethodString.equals("local")) {
            conf.setOutputMethod(Configuration.OutputMethods.LOCAL);
        } else {
            throw new RuntimeException(bundle.getString("CL.reportBug"));
        }

        String ouputUrlString = outputElement.getFirstChildElement("url", ns).getValue();

        URL outputUrl = null;
        try {
            outputUrl = new URL(ouputUrlString);
        } catch (MalformedURLException ex) {
            throw new RuntimeException(bundle.getString("CL.reportBug"));
        }

        conf.setRootUrl(outputUrl);

        Elements outputOptions = outputElement.getChildElements("option", ns);

        Map<String, String> options = new HashMap<String, String>(outputOptions.size());

        for (int i = 0; i < outputOptions.size(); i++) {
            Element outputOption = outputOptions.get(i);
            String option = outputOption.getAttributeValue("name", ns);
            String value = outputOption.getValue();
            options.put(option, value);
        }

        conf.setOutputMethodOptions(options);

        String databaseLocation = root.getFirstChildElement("databaseLocation", ns).getValue();
        
        conf.setDatabaseLocation(databaseLocation);

        String applicationLocation = root.getFirstChildElement("applicationLocation", ns).getValue();

        conf.setApplicationLocation(applicationLocation);

        return conf;
    }
}
